﻿using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace Core
{
    public class WinHider : IDisposable
    {
        #region Invokes

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string
        lpWindowName);

        [DllImport("user32.dll")]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion

        #region Win32 API Params

        //SetWindowPos consts
        class WINDOWPOS
        {
            public readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
            public readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
            public readonly IntPtr HWND_TOP = new IntPtr(0);
            public readonly IntPtr HWND_BOTTOM = new IntPtr(1);
        }

        class SWP
        {
            // From winuser.h
            public const UInt32 SWP_NOSIZE = 0x0001;
            public const UInt32 SWP_NOMOVE = 0x0002;
            public const UInt32 SWP_NOZORDER = 0x0004;
            public const UInt32 SWP_NOREDRAW = 0x0008;
            public const UInt32 SWP_NOACTIVATE = 0x0010;
            public const UInt32 SWP_FRAMECHANGED = 0x0020;  /* The frame changed: send WM_NCCALCSIZE */
            public const UInt32 SWP_SHOWWINDOW = 0x0040;
            public const UInt32 SWP_HIDEWINDOW = 0x0080;
            public const UInt32 SWP_NOCOPYBITS = 0x0100;
            public const UInt32 SWP_NOOWNERZORDER = 0x0200;  /* Don't do owner Z ordering */
            public const UInt32 SWP_NOSENDCHANGING = 0x0400;  /* Don't send WM_WINDOWPOSCHANGING */
        }

        //ShowWindow consts
        class SW
        {
            public const int SW_HIDE = 0;
            public const int SW_SHOWNORMAL = 1;
            public const int SW_SHOWMINIMIZED = 2;
            public const int SW_SHOWMAXIMIZED = 3;
            public const int SW_SHOWNOACTIVATE = 4;
            public const int SW_SHOW = 5;
            public const int SW_MINIMIZE = 6;
            public const int SW_SHOWMINNOACTIVE = 7;
            public const int SW_SHOWNA = 8;
            public const int SW_RESTORE = 9;
            public const int SW_SHOWDEFAULT = 10;
            public const int SW_FORCEMINIMIZE = 11;
        }
    
        #endregion

        // need this example for window pos 
        // SetWindowPos(hwnd, WINDOWPOS.HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

        private IntPtr hwnd;
        private bool hidden = false;
        private Thread hidethread;

        /// <summary>Constructor</summary>
        /// <param name="WindowName">Name of a window.</param>
        /// <param name="winstate">Pass true in order to hide the window on startup</param>
        public WinHider(string WindowName, bool hide) 
            : this(FindWindow(null, WindowName),hide)
        {}

        /// <summary>Constructor</summary>
        /// <param name="hwnd">Windowhandle</param>
        /// <param name="winstate">Pass true in order to hide the window on startup</param>
        public WinHider(IntPtr hwnd, bool hide)
        {
            this.hwnd = hwnd;
            if (hide) { this.HideWindow(); }
        }

        public IntPtr WindowHandle
        {
            get { return this.hwnd; }
            set
            {
                if (hidden && this.hwnd != IntPtr.Zero) { UnHideWindow(); } 
                this.hwnd = value; 
            }  
        }

        public bool IsHidden
        {
            get { return this.hidden; }
        }

        /// <summary>Unhides the window </summary>
        public bool UnHideWindow()
        {
            if (hidden)
            {
                if (hwnd != IntPtr.Zero)
                {
                    hidden = false;
                    return ShowWindow(hwnd, SW.SW_SHOWNOACTIVATE);
                }
            }
            return false;
        }

        /// <summary>Hides the window </summary>
        public bool HideWindow()
        {
            if (!hidden)
            {
                if (hwnd != IntPtr.Zero)
                {
                    MinimizeWindow();
                    Thread.Sleep(1000);
                    hidden = true;
                    hidethread = new Thread(new ThreadStart(HideWorker));
                    hidethread.Priority = ThreadPriority.Lowest;
                    hidethread.Start();
                    return true;
                }
            }
            return false;
        }

        public bool MinimizeWindow()
        {
            if (hwnd != IntPtr.Zero)
            {
                return ShowWindow(hwnd, SW.SW_SHOWMINIMIZED);
            }
            return false;
        }

        public void Dispose()
        {
            if (hidden)
            {
                UnHideWindow();
                if (hidethread != null)
                {
                    if (hidethread.IsAlive)
                    {
                        hidethread.Abort();
                        hidethread.Join();
                    }
                }
            }
        }

        private void HideWorker()
        {
            try
            {
                while (hidden)
                {
                    ShowWindow(hwnd, SW.SW_HIDE);
                    Thread.Sleep(1000);
                }
            }
            catch (Exception) { }
        }
    }
}
